#include"TcpServer.h"
#include"TcpServerMediator.h"
#include"packDef.h"
#include<process.h>
TcpServer::TcpServer(INetMediator* pMediator) :m_sockListen(INVALID_SOCKET),m_isStop(false)
{
	m_pMediator = pMediator;
}
TcpServer::~TcpServer()
{
	UnInitNet();
}
//初始化网络、加载库、创建套接字、绑定ip地址、监听、创建接收连接线程
bool TcpServer::InitNet()
{
	//1、加载库
	WORD wVersionRequested = { 0 };
	WSADATA wsaData = { 0 };
	int err = -1;

	/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
	wVersionRequested = MAKEWORD(2, 2);

	err = WSAStartup(wVersionRequested, &wsaData);	//WSA windows socket api
	if (err != 0) {
		/* Tell the user that we could not find a usable */
		/* Winsock DLL.                                  */
		printf("WSAStartup failed with error: %d\n", err);
		return false;
	}

	/* Confirm that the WinSock DLL supports 2.2.*/
	/* Note that if the DLL supports versions greater    */
	/* than 2.2 in addition to 2.2, it will still return */
	/* 2.2 in wVersion since that is the version we      */
	/* requested.                                        */

	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
		/* Tell the user that we could not find a usable */
		/* WinSock DLL.                                  */
		printf("Could not find a usable version of Winsock.dll\n");
		WSACleanup();
		return false;
	}
	else
		printf("The Winsock 2.2 dll was found okay\n");


	//2、创建套接字
	m_sockListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (INVALID_SOCKET == m_sockListen)
	{
		printf("socket error: %d\n", WSAGetLastError());
		WSACleanup();
		return false;
	}
	else
	{
		printf("socket succeded\n");
	}
	//3、绑定ip地址
	sockaddr_in server;
	server.sin_family = AF_INET;
	server.sin_port = htons(_DEF_TCP_PORT);//将整型变量从主机字节序转换成网络字节序
	server.sin_addr.S_un.S_addr = INADDR_ANY;//绑定任意网卡

	err = bind(m_sockListen, (sockaddr*)&server, sizeof(server));
	if (SOCKET_ERROR == err)
	{
		printf("socket error: %d\n", WSAGetLastError());
		closesocket(m_sockListen);
		WSACleanup();
		return false;
	}
	else
	{
		printf("bind succeded\n");
	}
	//4、监听——listen
	if (SOCKET_ERROR == listen(m_sockListen, 10))
	{
		printf("listen error: %d\n", WSAGetLastError());
		closesocket(m_sockListen);
		WSACleanup();
		return false;
	}
	else
	{
		printf("listen succeded\n");
	}

	//5、创建线程接受连接
	//服务器一直开着，所以要一直接受连接 ，接受连接本身也是阻塞函数，所以要创建线程
	HANDLE handle = (HANDLE)_beginthreadex(NULL, 0, &AcceptThread, this, 0, NULL);
	if (handle) {
		m_hThreadHandleList.push_back(handle);
	}
	return true;
}
//接受连接线程，
unsigned int __stdcall TcpServer::AcceptThread(void* lpvoid) {

	TcpServer* pThis = (TcpServer*)lpvoid;
	sockaddr_in clientAddr;
	int sddrSize = sizeof(clientAddr);

	while (!pThis->m_isStop) {
		//1、接受连接
		SOCKET sockClient = accept(pThis->m_sockListen, (sockaddr*)&clientAddr, &sddrSize);
		cout << "ip:" << inet_ntoa(clientAddr.sin_addr) << " connecct success" << endl;
		//2、给每个客户端创建一个接收数据的线程
		unsigned int nThreadId = 0;
		HANDLE handle = (HANDLE)_beginthreadex(NULL, 0, &RecvThread, pThis, 0, &nThreadId);
		if (handle) {
			//保存客户端句柄
			pThis->m_hThreadHandleList.push_back(handle);
			//保存客户端的socket
			pThis->m_mapThreadIdToSocket[nThreadId] = sockClient;
		}
	}
	return 0;
}
//客户端接收数据的线程函数
unsigned int __stdcall TcpServer::RecvThread(void* lpvoid)
{
	TcpServer* pThis = (TcpServer*)lpvoid;
	pThis->RecvData();
	return 0;
}

//关闭网络
void TcpServer::UnInitNet()
{
	//1、退出线程
	m_isStop = true;
	for (auto ite = m_hThreadHandleList.begin(); ite != m_hThreadHandleList.end();)
	{
		if (*ite)
		{
			if (WAIT_TIMEOUT == WaitForSingleObject(*ite, 100))
			{
				TerminateThread(*ite, -1);
			}
			CloseHandle(*ite);
			*ite = NULL;
		}
		ite = m_hThreadHandleList.erase(ite);
	}

	//2、关闭socket

	if (m_sockListen && m_sockListen != INVALID_SOCKET)
	{
		closesocket(m_sockListen);
	}
	for (auto ite = m_mapThreadIdToSocket.begin(); ite != m_mapThreadIdToSocket.end();)
	{
		if (ite->second && ite->second != INVALID_SOCKET)
		{
			closesocket(ite->second);
		}
		ite = m_mapThreadIdToSocket.erase(ite);
	}

	//3、卸载库
	WSACleanup();
}

//发送数据
bool TcpServer::SendData(long ISendIp, char* buf, int nLen)
{
	//1、参数校验
	if (!buf || nLen < 0) {
		return false;
	}

	//2、先发包大小
	if (send(ISendIp, (char*)&nLen, sizeof(int), 0) <= 0) {
		return false;
	}
	//3、再发包内容
	if (send(ISendIp,buf, nLen, 0) <= 0) {
		return false;
	}

	return true;
}



//接收数据
void TcpServer::RecvData()
{
	// 1、休眠 因为创建线程以后，立即就执行线程函数，但是把线程id和socket存入map 需要一点时间 目的:防止当前socket 还未保存取出空值
	Sleep(100);
	//2、从map中取出当前线程对应的socket
	SOCKET sock = m_mapThreadIdToSocket[GetCurrentThreadId()];
	if (!sock || sock == INVALID_SOCKET) {
		return;
	}

	int nRecvNum = 0;
	int nPckSize = 0;
	int offset = 0;
	while (!m_isStop) {
		//接受包大小
		nRecvNum = recv(sock, (char*)&nPckSize, sizeof(int), 0);
		if (nPckSize > 0) {
			//再接收包内容
			char* buf = new char[nPckSize];
			while (nPckSize) {
				nRecvNum = recv(sock, buf + offset, nPckSize, 0);
				if (nRecvNum > 0) {
					offset += nRecvNum;
					nPckSize -= nRecvNum;
				}
			}
			//接收完一个完整的包，数据发送给中介者类，offset清零
			this->m_pMediator->DealData(sock,buf,offset);
			offset = 0;//一定要记得清零

		}
	}
}
